"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RegisterController = void 0;
// 解析 body
var body_parser_1 = __importDefault(require("body-parser"));
// 解析表单
var connect_multiparty_1 = __importDefault(require("connect-multiparty"));
// 解析 cookie
var cookie_parser_1 = __importDefault(require("cookie-parser"));
var express_1 = __importDefault(require("express"));
var decorator_1 = require("./decorator");
var common_1 = require("./common");
function initExpress(app) {
    // 设置只执行一次
    if (global.IS_INIT_EXPRESS)
        return;
    global.IS_INIT_EXPRESS = true;
    // 解析 cookie
    app.use((0, cookie_parser_1.default)());
}
function getParamByName(obj) {
    return function (paramName) {
        if (paramName && paramName.trim()) {
            try {
                return obj[paramName];
            }
            catch (error) {
                return undefined;
            }
        }
        else {
            return obj;
        }
    };
}
function getParams(req, res, next, paramMetas) {
    var paramMap = {
        request: getParamByName(req),
        response: getParamByName(res),
        query: getParamByName(req.query),
        body: getParamByName(req.body),
        cookie: getParamByName(req.cookies),
        header: getParamByName(req.headers),
        params: getParamByName(req.params),
        next: function () { return next; }
    };
    // 按下标排序
    return paramMetas.sort(function (a, b) {
        return a.paramIndex - b.paramIndex;
    }).map(function (paramMeta) {
        return paramMap[paramMeta.paramType](paramMeta.paramName);
    });
}
function RegisterController(app, Constructor) {
    initExpress(app);
    var target = new Constructor();
    var Controller = target.constructor;
    var meta = (0, decorator_1.getMeta)(Controller);
    var baseRouter = express_1.default.Router();
    var _loop_1 = function (methodName) {
        var subRouter = express_1.default.Router();
        var methodMeta = meta.routes[methodName];
        var method = target[methodName];
        var httpMethod = subRouter[methodMeta.httpMethod].bind(subRouter);
        if (methodMeta.dataFormat === decorator_1.DataFormat.FORMDATA) {
            // 解析表单
            subRouter.use((0, connect_multiparty_1.default)());
        }
        else {
            // 解析 body
            subRouter.use(body_parser_1.default.json());
            subRouter.use(body_parser_1.default.urlencoded({ extended: false }));
        }
        methodMeta.midwares.push(function (req, res, next) {
            var handle = method.apply(target, getParams(req, res, next, methodMeta.params));
            // 普通请求只执行异步方法
            if (handle instanceof Promise) {
                handle.then(function (result) {
                    if (result instanceof common_1.Result) {
                        res.json(result);
                    }
                    else if (methodMeta.isCustom) {
                        // 自定义处理
                    }
                    else {
                        next('控制器方法返回值不是 Result 类的实例');
                    }
                }).catch(function (error) {
                    next(error);
                });
            }
            else {
                next('控制器只执行异步方法，请使用 async await 或者方法返回 Promise');
            }
        });
        httpMethod.apply(target, __spreadArray([methodMeta.subUrl], meta.midwares.concat(methodMeta.midwares), true));
        baseRouter.use(meta.baseUrl, subRouter);
    };
    for (var methodName in meta.routes) {
        _loop_1(methodName);
    }
    app.use(baseRouter);
}
exports.RegisterController = RegisterController;
